home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / STREAM13.ARJ / STREAMS.DOC < prev    next >
Text File  |  1992-05-18  |  40KB  |  1,095 lines

  1. STREAMS - TP 6.0/TPW 1.0 unit to supplement TurboVision/ObjectWindows streams
  2.  
  3.      Version 1.3.  Copyright D.J. Murdoch (1992).
  4.  
  5. DESCRIPTION
  6.  
  7.      "Wierd Stream Tricks" might be a good name for this unit.  It
  8.      contains a miscellaneous collection of objects and procedures, all
  9.      on a theme of adding functionality to the streams in Borland's
  10.      Turbo Pascal libraries TurboVision and ObjectWindows.
  11.  
  12. LICENSE
  13.  
  14.      This unit is *not* public domain code.  You may use it for
  15.      non-profit purposes at no charge if credit is granted, but
  16.      written permission must be obtained from me for use of this unit in
  17.      commercial products.
  18.  
  19.      A lot of the code in this unit is code that's been made freely
  20.      available by others, some of it under their copyright, other parts
  21.      public domain.  As far as I know, all code included here may be
  22.      used under non-commercially for free.  See the list of credits at
  23.      the end for all the (known) authors.
  24.  
  25.      This is the second release of the STREAMS unit.  There are probably
  26.      still bugs; I would really appreciate reports of any, or other
  27.      suggestions for improvement.  Please send either one to me at one
  28.      of the following addresses:
  29.  
  30.        dmurdoch@watstat.waterloo.edu (Internet)
  31.        71631,122 (Compuserve)
  32.        DJ Murdoch at Fidonet node 1:221/177.40
  33.  
  34.        D. J. Murdoch
  35.        79 John St. W.
  36.        Waterloo, Ontario, Canada
  37.        N2L 1B7
  38.  
  39.  
  40. SUMMARY
  41.  
  42. Hierarchy
  43.  
  44.    TStream                  (from Objects)
  45.      TFilter                Base type for filters
  46.        TEncryptFilter       Encrypts as it writes; decrypts as it reads
  47.        TLZWFilter           Compresses as it writes; expands as it reads
  48.        TTextFilter          Provides text file interface to stream
  49.        TLogFilter           Provides logging of text file activity
  50.        TBitFilter           Allows bit-oriented I/O
  51.        TDupFilter           Duplicates output, checks for matching input
  52.        TSequential          Filter that doesn't allow Seek
  53.          TChksumFilter      Calculates 8 or 16 bit checksum for reads/writes
  54.          TCRC16Filter       Calculates XMODEM style 16 bit CRC
  55.          TCRCARCFilter      Calculates ARC style 16 bit CRC
  56.          TCRC32Filter       Calculates ZIP & Zmodem style 32 bit CRC
  57.      TNulStream             Eats writes, returns constant on reads
  58.      TRAMStream             Stream in memory
  59.      TXMSStream             Stream in XMS (extended) memory
  60.      TDOSStream             (from Objects)
  61.        TBufStream           (from Objects)
  62.          TNamedBufStream    Buffered file stream that knows its name
  63.            TTempBufStream   Buffered file stream that erases itself when done
  64.  
  65. Procedures & functions:
  66.  
  67.    TempStream      allocates a temporary stream
  68.    OvrInitStream   like OvrInitEMS, but buffers overlays on a stream
  69.                    May be called several times to buffer different
  70.                    segments on different streams.
  71.    OvrDetachStream detaches stream from overlay system
  72.    OvrDisposeStreams detaches all streams from overlay system and disposes of
  73.                    them
  74.    OvrSizeNeeded   Calculates the size needed to load the rest of the segments
  75.                    to a stream
  76.    OvrLoadAll      immediately copies as many overlay segments to the stream
  77.                    as will fit
  78.    xms_MemAvail    returns the number of 1K blocks of XMS memory available
  79.    xms_MaxAvail    returns size in Kb of the largest block of XMS memory
  80.  
  81. CONTENTS
  82.      0.  Files in archive
  83.              a list of the files that should accompany this one
  84.      1.  TFilter
  85.              a generic object to act as a filter to a stream
  86.      2.  TEncryptFilter
  87.              a filter which does simple encryption/decryption
  88.      3.  TLZWFilter
  89.              a filter which does LZW compression/decompression
  90.      4.  TTextFilter
  91.              a filter to provide the Read/ReadLn/Write/WriteLn
  92.              interface to a stream
  93.      5.  TLogFilter
  94.              a filter to allow logging of activity on text files
  95.      6.  TBitFilter
  96.              a filter to allow bit level I/O to a stream
  97.      7.  TDupFilter
  98.              a filter to duplicate output, check for duplicate input
  99.      8.  TSequential
  100.              a generic filter that can't Seek
  101.      9.  Checksum/CRC filters:
  102.              a collection of filters which calculate checksums and CRC
  103.              values as the data goes by
  104.     10.  TNulStream
  105.              a stream which counts data written to it, and which
  106.              returns a constant if you read
  107.     11.  TRAMStream
  108.              a stream which resides entirely in RAM
  109.     12.  TXMSStream
  110.              a stream which keeps its data in XMS memory
  111.     13.  xms_MemAvail and xms_MaxAvail
  112.              procedures to show how much XMS memory is free
  113.     14.  TNamedBufStream
  114.              a buffered file stream which knows its own name
  115.     15.  TTempBufStream
  116.              a temporary buffered file stream, which deletes itself when
  117.              done
  118.     16.  TempStream
  119.              a procedure to allocate a temporary stream, in RAM, EMS, or
  120.              on disk, according to a specified preference
  121.     17.  OvrInitStream and related procedures
  122.              procedures to allow overlays to be buffered on any
  123.              stream or combination of streams
  124.     18.  Miscellaneous constants and types
  125.  
  126.     19.  Release history and credits
  127.  
  128. 0.  FILES IN ARCHIVE
  129.  
  130.   Streams.doc   - this file
  131.   Streams.pas   - main source file for unit
  132.   Lzwstrea.asm  - source for LZW compression
  133.   Xmsstrm.inc   - source for XMS stream
  134.   Crc16.asm     - source for 16 bit CRC
  135.   Crc32.asm     - source for 32 bit CRC
  136.   Crcarc.asm    - source for ARC-style 16 bit CRC
  137.   Lzwstrea.obj  - assembled code for external linking
  138.   Crc16.obj     -     "      "    "     "        "
  139.   Crcarc.obj    -     "      "    "     "        "
  140.   Crc32.obj     -     "      "    "     "        "
  141.  
  142.   Demo programs:
  143.  
  144.   Encrypt.pas   -  encryption program, using TEncryptFilter
  145.   Compress.pas  -  file compressor, using TLZWFilter
  146.   Huffman.pas   -  defines a Huffman encoding filter, using TBitFilter
  147.   HuffComp.pas  -  file compressor using THuffmanFilter
  148.   Logdemo.pas   -  simple demo of TLogFilter
  149.   Ovrdemo.pas   -  simple demo of multiple overlay files
  150.    ovr1.pas     -  one overlaid unit
  151.    ovr2.pas     -  a second overlaid unit
  152.  
  153.  
  154. 1.  TFilter = object(TStream)
  155.  
  156.      "Filters" are programs which take a file as input and produce a new
  157.      file as output.  TFilter is an adaptation of this idea to streams.
  158.      Every TFilter has a base stream, which can be any kind of stream.
  159.      Every TFilter is itself a stream, which means you can read and
  160.      write to it.  When you do, it just relays your request to the base
  161.      stream.
  162.  
  163.      One use of this is in the fact that you can make descendants
  164.      of TFilter which massage the data on the way to and from the Base.
  165.      Just override the Read and Write (and possibly other) methods, and
  166.      you can make changes to the data flowing to or from *any* kind of
  167.      stream.  No need for special coding for an TEMSStream, or for a
  168.      TDOSStream, or whatever.  Your code can act on any of them.
  169.      Examples of things to do are in the Streams unit:  encryption
  170.      (TEncryptFilter) and LZW compression (TLZWFilter).
  171.  
  172.      The other main use is to add other kinds of functionality to a
  173.      stream.  You can't use the formatting capabilities of ReadLn and
  174.      WriteLn with standard streams, but if you use a TTextFilter (see
  175.      below) you can.
  176.  
  177.      FIELDS
  178.  
  179.      Base : PStream;
  180.  
  181.        TFilter.Base holds the pointer to the base stream.
  182.  
  183.      StartOfs : longint;
  184.  
  185.        TFilter.StartOfs holds the offset in the base stream of offset 0
  186.        in the filter.  This allows multiple filters to work on the same
  187.        stream; one could work at offset 0, another at offset 1000, etc.
  188.        Just position the base to the desired starting offset before
  189.        initializing the filter.
  190.  
  191.      METHODS
  192.  
  193.      Constructor Init(ABase: PStream);
  194.  
  195.        TFilter.Init sets Base to point to ABase^, and sets StartOfs to
  196.        the current position of the base stream.
  197.  
  198.      Destructor Done; virtual;
  199.  
  200.        If Base is not nil, then TFilter.Done calls Flush, then disposes
  201.        of the base stream before calling TStream.Done for itself.
  202.  
  203.      Function CheckStatus : boolean; virtual;
  204.  
  205.        Returns true if status is stOK.  If it is, but the base status is
  206.        not stOK, then it assumes that someone has called a Reset for the
  207.        filter, so it calls Reset for the base stream.  Borland should
  208.        have made Reset virtual, and this kludge wouldn't have been
  209.        necessary!
  210.  
  211.      Procedure CheckBase;
  212.  
  213.        Checks the base stream for an error.  If Base^.status is not
  214.        stOK, then it calls Error with Code=stBaseError and
  215.        Info=Base^.status.
  216.  
  217.      Function GetPos  : longint; virtual;
  218.      Function GetSize : longint; virtual;
  219.      Procedure Read(var buf; count : word); virtual;
  220.      Procedure Seek(pos: longint); virtual;
  221.      Procedure Truncate; virtual;
  222.      Procedure Write(var buf; count: word); virtual;
  223.      Procedure Flush; virtual;
  224.  
  225.        These methods all call the corresponding method in the base
  226.        stream.  Offsets are translated using StartOfs.  Before the call,
  227.        CheckStatus is called to propagate any Reset to the base; after
  228.        the call, CheckBase is called to propagate any errors to the
  229.        filter from the base.
  230.  
  231. 2.  TEncryptFilter = object(TFilter)
  232.  
  233.        This is a filter which does simple encryption/decryption on the
  234.        base stream.  The encryption method is to XOR each byte with a
  235.        Random(256) value; the starting RandSeed is the key for the
  236.        encryption.
  237.  
  238.      FIELD
  239.  
  240.      key : longint;
  241.  
  242.        The key is used as a Randseed replacement value.  Randseed itself
  243.        is left unmodified by Read and Write.
  244.  
  245.      METHODS
  246.  
  247.      Constructor Init(Akey:longint; ABase:PStream);
  248.  
  249.        The value AKey is used as the starting key for byte 0 of the
  250.        filter.  Anything read from ABase is decrypted using this key;
  251.        anything written to it is encrypted.
  252.  
  253.      Procedure Read(var buf; count : word); virtual;
  254.      Procedure Seek(pos : longint); virtual;
  255.      Procedure Write(var buf; count: word); virtual;
  256.  
  257.        These methods all encrypt/decrypt and update the value of Key to
  258.        correspond to the new position in the stream.  The encryption
  259.        method uses the same algorithm for encryption as for decryption.
  260.        TEncryptFilter.Seek is fairly slow, because it updates the Key
  261.        once for every byte difference between the current position and
  262.        the new position.  Moving backwards is slower, because the update
  263.        algorithm is written in Pascal, not assembler as is the forward
  264.        algorithm.
  265.  
  266. 3.  TLZWFilter = object(TFilter)
  267.  
  268.        This is a filter which does LZW compression as it writes to and
  269.        decompression as it reads from the base stream.  The LZW code is
  270.        an adaptation of Wilbert van Leijen's implementation of the 12
  271.        bit LZW algorithm.  It's quite fast, though not as fast as
  272.        Wilbert's version; it gets slowed down a lot by having to save
  273.        its state after every Read and Write operation.  You're best off
  274.        writing large chunks to it to take advantage of Wilbert's
  275.        excellent code.  (Historical note:  Trying to rewrite this was
  276.        what inspired me to write FULLDB, a program which allows source
  277.        level debugging of external .ASM files. -djm)
  278.  
  279.        Each TLZWFilter takes over 28700 bytes of memory, because it
  280.        keeps extensive tables to record the current state.
  281.  
  282.        One limitation of the TLZWFilter is that it can only be opened in
  283.        read or write mode, and Seek cannot be used in write mode.  If
  284.        this doesn't suit your application, you might want to flesh out
  285.        the demo Huffman encoder (HUFFMAN.PAS), since it does allow
  286.        random access.
  287.  
  288.      FIELDS
  289.  
  290.      Mode : word;
  291.  
  292.        One of stOpenRead or stOpenWrite; the mode under which this
  293.        filter was opened.
  294.  
  295.      Size : longint;
  296.  
  297.        The size of the expanded stream.  This is the size that users of
  298.        the filter will see; if compression is working, it will generally
  299.        be bigger than Base^.GetSize.
  300.  
  301.      Position : longint;
  302.  
  303.        This is the position in the expanded stream.
  304.  
  305.      Tables : PLZWTables;
  306.  
  307.        This is a pointer to the tables used by the compression engine.
  308.        They're automatically allocated on the heap.
  309.  
  310.      METHODS
  311.  
  312.      Constructor Init(ABase:PStream; AMode:TOpenMode);
  313.  
  314.        Allocates Tables from the heap, and opens the compressor in
  315.        a mode of either stOpenRead or stOpenWrite.  If reading, a
  316.        signature and record of the uncompressed filesize is read from
  317.        the base to confirm that it is compressed by LZW, and to prime
  318.        the Tables.  If writing, the signature is written to the stream.
  319.  
  320.      Destructor Done; virtual;
  321.  
  322.        Flushes all data to the stream, and writes the uncompressed
  323.        filesize to the head of it before calling TFilter.done.
  324.  
  325.      Procedure Flush; virtual;
  326.      Function  GetPos: longint; virtual;
  327.      Function  GetSize:longint; virtual;
  328.      Procedure Read(var buf; count:word); virtual;
  329.      Procedure Seek(pos:longint); virtual;
  330.      Procedure Truncate; virtual;
  331.      Procedure Write(var buf; count: word); virtual;
  332.  
  333.        These methods all override the basic filter methods and
  334.        compress/decompress the data.  They check whether the operation
  335.        requested can be performed in the current mode, and call Error
  336.        with Code=stBadMode and Info=Mode if the operation is not
  337.        supported.
  338.  
  339.        Seek is not supported at all in Write mode.  In Read mode, it is
  340.        slow for seeking forwards, and very slow for seeking backwards:
  341.        it rewinds the file to the start and seeks forward from there by
  342.        expanding everything.
  343.  
  344.        Truncate is not supported in either mode, and always causes a
  345.        call to Error.
  346.  
  347.        Flush may only be called once; it changes Mode to 0, so any
  348.        further operations will fail.
  349.  
  350. 4.  TTextFilter = object(TFilter)
  351.  
  352.        This is a filter which provides a Read/ReadLn/Write/WriteLn
  353.        interface to a stream through its Textfile field.  Once the
  354.        filter is initialized, Textfile acts exactly like a text file in
  355.        the standard I/O procedures, but reads come from the stream, and
  356.        writes go to it.  All of the standard stream methods work as
  357.        well, by flushing the Textfile variable first.
  358.  
  359.      FIELD
  360.  
  361.      Textfile : Text;
  362.  
  363.        This is the dummy text file to use in Read/ReadLn/Write/WriteLn.
  364.  
  365.      METHODS
  366.  
  367.      Constructor Init(ABase:PStream; AName:String);
  368.  
  369.        Initializes the filter with base ABase.  The name AName is stored
  370.        as the name in the Textfile variable.
  371.  
  372.      Destructor Done; virtual;
  373.  
  374.        Closes the TextFile variable to flush any remaining data to the
  375.        stream.
  376.  
  377.      function GetPos : LongInt; virtual;
  378.      function GetSize : LongInt; virtual;
  379.      procedure Read(var Buf; Count : Word); virtual;
  380.      procedure Seek(Pos : LongInt); virtual;
  381.      procedure Truncate; virtual;
  382.      procedure Write(var Buf; Count : Word); virtual;
  383.  
  384.        Versions of the standard filter functions.
  385.  
  386. 5.  TLogFilter = object(TFilter)
  387.  
  388.        This filter allows logging of activity on text files to a stream.
  389.        Logging is done very transparently.  Once the TTextFilter is
  390.        initialized, you call the Log method to start logging a
  391.        particular text file, and the UnLog method to stop.  When logging
  392.        is in effect, any data read from or written to the text file is
  393.        copied to the stream.
  394.  
  395.        Multiple files may be logged to the same stream.  For example,
  396.        you can log both Input and Output, and keep a record of an
  397.        interactive session on the stream.
  398.  
  399.        It's also possible to log the same file to multiple streams.
  400.        Just create the different TLogFilter objects, and call their Log
  401.        methods with the same file as an argument.  If you then call
  402.        Unlog, you must do it in the *reverse* order to the order you
  403.        called Log, e.g.
  404.          S1^.log(output);
  405.          S2^.log(output);
  406.          S2^.unlog(output);
  407.          S1^.unlog(output);
  408.        is the correct order to log and unlog.
  409.  
  410.        One detail of the implementation may cause some trouble.  The
  411.        data is logged to the stream at the time it is written to disk by
  412.        the text file.  Since text files are buffered, this may not be
  413.        the time at which you write to the text file, and multiple text
  414.        files logged to the same stream may not have all data appearing
  415.        in the correct order.
  416.  
  417.      FIELD
  418.  
  419.      LogList : ^Text;
  420.  
  421.        This is a pointer to the first text file currently being logged.
  422.  
  423.      METHODS
  424.  
  425.      Constructor Init(ABase:PStream);
  426.  
  427.        Initializes the filter with a LogList of nil.
  428.  
  429.      Destructor done; virtual;
  430.  
  431.        Stops logging all text files by calling UnLog for each, and
  432.        closes and disposes of the base stream.
  433.  
  434.      Procedure Log(var F:text);
  435.  
  436.        Starts logging the text file F.  Continues until the UnLog method
  437.        is called or the file is closed or Assign'd.
  438.  
  439.      Function UnLog(var F:text):boolean;
  440.  
  441.        Stops logging the text file F.  Returns true if successful, false
  442.        if not.  Will fail if an Assign has been done to F, or F has been
  443.        closed, or F has already been Unlogged, or another stream has
  444.        started logging F and hasn't been UnLog'd yet.
  445.  
  446. 6.  TBitFilter = object(TFilter)
  447.  
  448.        This filter allows you to do bit-oriented I/O to a stream,
  449.        instead of the usual byte-oriented I/O.  A typical use might be
  450.        for a compression scheme:  if a word only takes the values 0 or
  451.        1, you can use a TBitFilter to be sure that it only takes up one
  452.        bit of the output file.
  453.  
  454.        If you use this filter, you can mix standard byte-oriented I/O
  455.        (Read, Write) with bit-oriented I/O (GetBit, GetBits, ReadBits,
  456.        PutBit, PutBits, WriteBits).  There's a substantial performance
  457.        penalty however, if the bytes you write to the stream aren't
  458.        aligned with the actual bytes in the base stream.
  459.  
  460.        One arbitrary choice was made:  the order of bits in a byte.
  461.        This object follows the 80x86 convention of least significant
  462.        part first, and considers the least significant bit (low bit) to
  463.        come before the most significant bit (high bit) within a byte.
  464.  
  465.      FIELDS
  466.  
  467.      BitPos : shortint;
  468.  
  469.        Position of stream relative to base file.  Negative values signal
  470.        that the buffer is unchanged from the file, positive values signal
  471.        that the file needs to be updated.  Zero signals an empty buffer.
  472.  
  473.      Mask : byte;
  474.  
  475.        The mask to use to extract the next bit from the buffer.
  476.  
  477.      Buffer : byte;
  478.  
  479.        A buffer to hold 8 bits.
  480.  
  481.      AtEnd : boolean;
  482.  
  483.        This flag is an efficiency hack.  A TBitFilter can write a single
  484.        bit anywhere in a file; this means that it has to read the
  485.        existing byte before writing a new one.  If it's doing a lot of
  486.        small writes at the end of the file, this can be incredibly slow,
  487.        because every one of those reads will fail.  The AtEnd flag
  488.        signals that the current position of the stream is the end of the
  489.        file, and a read isn't necessary.
  490.  
  491.        Normally, AtEnd is maintained internally, and you don't need to
  492.        worry about it.  However, if you increase the length of the base
  493.        stream other than by writes through the TBitFilter, you
  494.        *must* set AtEnd to false, so that the bit buffer is properly
  495.        initialized.  Calling Flush on the TBitFilter is sufficient to do
  496.        this, and would probably be a good idea before you fiddled with
  497.        the base anyways.
  498.  
  499.      METHODS
  500.  
  501.      Function GetBit : TBit;
  502.  
  503.        Type TBit is a 0 or a 1.  This function reads a single bit from
  504.        the stream.
  505.  
  506.      Function GetBits(count : byte): longint;
  507.  
  508.        This function reads up to 32 bits, and returns them in the
  509.        longint value.  The first bit read ends up in the least
  510.        significant bit of the result, and bits higher than the count
  511.        are zeroed.
  512.  
  513.      Procedure ReadBits(var buf; count : longint);
  514.  
  515.        This procedure reads up to 524288 bits (64K bytes) from the
  516.        stream into the buffer.  Reads are faster when they start on a
  517.        byte boundary.  Only the bytes that are affected by the
  518.        read will be modified, with the high bits of the last byte zeroed
  519.        if necessary.  For example, if you read fewer than 9 bits into a
  520.        word variable, the high byte of the word will be left untouched.
  521.  
  522.      Procedure PutBit(ABit : TBit);
  523.  
  524.        Write one bit to the stream.
  525.  
  526.      Procedure PutBits(Abits : longint; count : byte);
  527.  
  528.        Writes up to 32 bits to the stream.  Since ABits is a value
  529.        parameter, you can write the value of an expression directly to
  530.        the stream without storing it in an intermediate variable.
  531.  
  532.      Procedure WriteBits(var buf; count : longint);
  533.  
  534.        This procedure writes up to 524288 bits (64K bytes) to the
  535.        stream.  Writes are *much* faster if the starting bit is byte
  536.        aligned.
  537.  
  538.      Procedure SeekBit(bitpos:longint);
  539.  
  540.        Seek to a particular bit in the stream.
  541.  
  542.      Function GetBitPos : longint;
  543.  
  544.        Get the current stream position accurate to the nearest bit.
  545.  
  546.      Procedure CopyBits(var S:TBitFilter; Count:longint);
  547.  
  548.        Like CopyFrom, but for bits:  copies Count bits from S.
  549.  
  550.      Procedure ByteAlign;
  551.  
  552.        Seeks forward to the next byte boundary.  If the last byte
  553.        of the stream is only partially filled, it will be padded with
  554.        zero bits.
  555.  
  556.      Procedure Read(var Buf; Count : Word); virtual;
  557.      Procedure Write(var Buf; Count : Word); virtual;
  558.      Procedure Seek(Pos : LongInt); virtual;
  559.      Procedure Flush; virtual;
  560.  
  561.        Implement the standard byte-oriented functions.  Note that if the
  562.        base stream is not byte-aligned at the start or a read/write,
  563.        they will split each byte between two in the output stream.
  564.  
  565.      Procedure PrepareBuffer(ForRead:boolean);
  566.  
  567.        Internal method to prepare the buffer for a read or a write.
  568.  
  569. 7.  TDupFilter = object(TFilter)
  570.  
  571.        A filter which duplicates writes to two base streams, and checks
  572.        that data read from the two base streams matches.  The match test
  573.        is a virtual method, so a descendant could implement a different
  574.        test if desired.
  575.  
  576.      FIELDS
  577.  
  578.      Base2 : PStream;
  579.  
  580.         This is a pointer to the second base stream.  I/O is done first
  581.         to Base^, then to Base2^.
  582.  
  583.      Startofs2 : Longint;
  584.  
  585.         Corresponds to TFilter.StartOfs, but applies to Base2^:  gives
  586.         the offset corresponding to the filter's offset of 0.
  587.  
  588.      METHODS
  589.  
  590.      constructor Init(ABase, Abase2 : PStream);
  591.  
  592.         Sets the two base streams and the start offset variables.
  593.  
  594.      destructor Done; virtual;
  595.  
  596.         Flushes the filter, then disposes of both bases if they're not
  597.         nil.
  598.  
  599.      function MisMatch(var buf1,buf2; count:word):word; virtual;
  600.  
  601.         Checks for a mismatch between the two buffers.  Returns
  602.         the byte number of the mismatch (1 based), or 0 if they
  603.         test equal.  This default method checks for an exact match.
  604.  
  605.      procedure Read(var Buf; Count : Word); virtual;
  606.  
  607.         Reads from Base into the buffer, then does a corresponding read
  608.         from Base2 into a local buffer calling MisMatch to check for a
  609.         mismatch.  If one is found, calls the Error method to signal an
  610.         stMisMatch error, with the Info word equal to the position of
  611.         the mismatch in the current buffer.
  612.  
  613.         Unless a base error occurs, the two bases will be left
  614.         synchronized at the position following the data just read.
  615.  
  616.       procedure Seek(Pos : LongInt); virtual;
  617.       procedure Truncate; virtual;
  618.       procedure Write(var Buf; Count : Word); virtual;
  619.       procedure Flush; virtual;
  620.  
  621.         Standard methods applied to both bases.
  622.  
  623.       function CheckStatus : Boolean; virtual;
  624.  
  625.         Checks the status of the filter, and assures that both bases are
  626.         okay if status is stOK.
  627.  
  628.       procedure CheckBase2;
  629.  
  630.         Like TFilter.CheckBase, but operates on base2 and signals
  631.         stBase2Error.
  632.  
  633. 8.  TSequential
  634.  
  635.         This is a very simple descendant of TFilter:  the only
  636.         difference is that it signals stUnsupported if the Seek method
  637.         is called.  It's used as a base for the filters below, which can
  638.         only work sequentially.
  639.  
  640.       METHOD
  641.  
  642.       procedure Seek(pos:longint); virtual;
  643.  
  644.         Signals stUnsupported by calling Error if ever called.
  645.  
  646. 9.  Checksum/CRC filters
  647.  
  648.         These are four filters, TChkSumFilter, TCRC16Filter,
  649.         TCRCARCFilter, and TCRC32Filter, which can be used to calculate
  650.         checksums and cyclic redundancy checks (CRCs) on the stream of
  651.         data passing through the filter in either reads or writes.
  652.  
  653.         All three CRC filters are based on code by a collection of
  654.         authors:  Stephen Satchell, Chuck Forsberg, Mark G. Mendel, R.
  655.         P. Byrne, J. R. Louvau and probably others.  Edwin T. Floyd
  656.         collected them together and translated them to TASM.  The
  657.         CRC*.ASM files include more comments about sources and usage.
  658.  
  659.         The basic calculations are also available in the interfaced
  660.         procedures UpdateChksum, UpdateCRC16, UpdateCRCARC, UpdateCRC32.
  661.         See the source code for the calling details.
  662.  
  663.       TChkSumFilter = object(TSequential)
  664.  
  665.         TChkSumFilter calculates a 16 bit sum of all the bytes read from
  666.         or written to the stream.
  667.  
  668.       TCRC16Filter = object(TSequential)
  669.  
  670.         This filter calculates the same 16 bit CRC as used in XModem and
  671.         its descendants.
  672.  
  673.       TCRCARCFilter = object(TSequential)
  674.  
  675.         This filter calculates the 16 bit CRC used by ARC.
  676.  
  677.       TCRC32Filter = object(TSequential)
  678.  
  679.         This filter calculates the 32 bit CRC used by PKZIP and ZModem.
  680.  
  681.       FIELDS
  682.  
  683.       TChkSumFilter.Chksum : word;
  684.  
  685.         The 16 bit sum of all bytes passing through the filter.  If an 8
  686.         bit checksum is required, get the low byte of Chksum by using
  687.         Byte(Chksum).
  688.  
  689.       TCRC16Filter.CRC16 : word;
  690.  
  691.         The XModem-style 16 bit CRC of all bytes passing through the
  692.         filter.
  693.  
  694.       TCRCARCFilter.CRCARC : word;
  695.  
  696.         The ARC-style 16 bit CRC of all bytes passing through the
  697.         filter.
  698.  
  699.       TCRC32Filter.CRC32 : longint;
  700.  
  701.         The PKZIP and ZModem-style 32 bit CRC of all bytes passing
  702.         through the filter.  Note that the value should be inverted
  703.         before use (i.e. use "not CRC32" rather than "CRC32") for
  704.         compatibility with those programs.
  705.  
  706.       METHODS
  707.  
  708.       constructor TChkSumFilter.Init(ABase : PStream;AChksum:word);
  709.       constructor  TCRC16Filter.Init(ABase : PStream;ACRC16:word);
  710.       constructor TCRCARCFilter.Init(ABase : PStream;ACRCARC:word);
  711.       constructor  TCRC32Filter.Init(ABase : PStream;ACRC32:word);
  712.  
  713.         These constructors all initialize the filter, and set the
  714.         sum or CRC to the given value.  Typically the first three would
  715.         start with a value of 0; PKZIP and ZModem start the 32 bit CRC
  716.         with a value of $FFFFFFFF.
  717.  
  718.       procedure Read(var Buf; Count : Word); virtual;
  719.       procedure Write(var Buf; Count : Word); virtual;
  720.  
  721.         All four filters override just these two methods.  Both update
  722.         the sum or CRC if the Read/Write is successful.
  723.  
  724. 10.  TNulStream = object(TStream)
  725.  
  726.        A stream which eats your writes, and returns a constant if you
  727.        read from it.  (Suggested by Stefan Boether.)
  728.  
  729.        I can see two uses for this stream.  Stefan suggested using it to
  730.        count bytes:  if you're not sure how much space something will
  731.        take when written out, write it to a TNulStream, and then read
  732.        the size to find out.  I use it differently in the TempStream
  733.        code:  there, it's used to initialize another stream to a fixed
  734.        value.  I just copy as many bytes as I need from a TNulStream.
  735.  
  736.      FIELDS
  737.  
  738.      position : longint;
  739.  
  740.        The current position of the stream.  This is increased by both
  741.        reads and writes.  It's also used as the current size of the
  742.        stream.
  743.  
  744.      value : byte;
  745.  
  746.        The value which will be used to fill any read request.
  747.  
  748.      METHODS
  749.  
  750.      Constructor init(Avalue : byte);
  751.  
  752.        Initialize the stream with value=Avalue.
  753.  
  754.      Destructor done; virtual;
  755.  
  756.        Dispose of the stream.
  757.  
  758.      Function getpos : longint; virtual;
  759.      Function getsize : longint; virtual;
  760.      Procedure read(var buf; count : word); virtual;
  761.      Procedure seek(pos: longint); virtual;
  762.      Procedure write(var buf; count: word); virtual;
  763.  
  764.        Implement the basic stream functions.
  765.  
  766.  
  767. 11.  TRAMStream = object(TStream)
  768.  
  769.        A stream which resides entirely in RAM, either maintaining its
  770.        own buffer, or using a predefined buffer.  The maximum length
  771.        is 65520 bytes.
  772.  
  773.      FIELDS
  774.  
  775.      cp : word;
  776.  
  777.        The current pointer for the stream.
  778.  
  779.      size : word;
  780.  
  781.        The current size of the stream.
  782.  
  783.      alloc : word;
  784.  
  785.        The size of the allocated block of memory.
  786.  
  787.      buffer : Pbyte_array;
  788.  
  789.        A pointer to the block of memory holding the stream data.
  790.  
  791.      OwnMem : Boolean;
  792.  
  793.        Indicates whether the stream "owns" the buffer, and should dispose
  794.        of it in the Done destructor.
  795.  
  796.      METHODS
  797.  
  798.      Constructor init(Asize : word);
  799.  
  800.        Attempt to initialize the stream to a block size of Asize;
  801.        initial stream size and position are 0.
  802.  
  803.      Constructor UseBuf(Abuffer : pointer; Asize : word);
  804.  
  805.        Set up the stream using the given buffer; OwnMem is set to false,
  806.        so that the memory will not be disposed when done.
  807.  
  808.      Destructor done; virtual;
  809.  
  810.        Dispose of the stream, and if OwnMem is true, the data buffer.
  811.  
  812.      Function getpos : longint; virtual;
  813.      Function getsize : longint; virtual;
  814.      Procedure read(var buf; count : word); virtual;
  815.      Procedure seek(pos: longint); virtual;
  816.      Procedure truncate; virtual;
  817.      Procedure write(var buf; count: word); virtual;
  818.  
  819.        Implement the basic stream functions.
  820.  
  821.  
  822. 12.  TXMSStream = object(TStream)
  823.  
  824.        A stream which keeps its data in XMS (extended) memory.
  825.  
  826.      FIELDS
  827.  
  828.      Handle : word;
  829.  
  830.        The handle used by the XMS memory manager for the stream's block
  831.        of data.
  832.  
  833.      MaxBlocks : word;
  834.  
  835.        The maximum number of 1K blocks of memory to allocate.
  836.  
  837.      BlocksUsed : word;
  838.  
  839.        The number of 1K blocks of memory currently allocated.  Always
  840.        allocates at least 1 byte more than Size.
  841.  
  842.      Size : longint;
  843.  
  844.        The current size of the stream.
  845.  
  846.      Position : longint;
  847.  
  848.        The current position of the stream.
  849.  
  850.      METHODS
  851.  
  852.      Constructor init(AMaxBlocks : word);
  853.  
  854.        Attempt to initialize the stream to a block size of with the
  855.        given value for MaxBlocks.  The initial stream size and position
  856.        are 0, and one block is allocated.
  857.  
  858.      Destructor done; virtual;
  859.  
  860.        Dispose of the stream, and release the XMS memory.
  861.  
  862.      Function getpos : longint; virtual;
  863.      Function getsize : longint; virtual;
  864.      Procedure read(var buf; count : word); virtual;
  865.      Procedure seek(pos: longint); virtual;
  866.      Procedure truncate; virtual;
  867.      Procedure write(var buf; count: word); virtual;
  868.  
  869.        Implement the basic stream functions.
  870.  
  871.      Procedure NewBlock;
  872.  
  873.        Internal method to increase the stream's allocation by one block.
  874.  
  875.      Procedure FreeBlock;
  876.  
  877.        Internal method to decrease the stream's allocation by one block.
  878.        Doesn't check if the allocated size falls below Size.
  879.  
  880.  
  881. 13.  xms_MemAvail and xms_MaxAvail
  882.  
  883.        These procedures are analogous to the MemAvail and MaxAvail
  884.        procedures in the System unit.  They report on available XMS
  885.        memory, in units of 1K blocks.
  886.  
  887. 14.  TNamedBufStream = object(TBufStream)
  888.  
  889.        A simple descendant of TBufStream which knows its own name.
  890.  
  891.      FIELD
  892.  
  893.      filename : PString  { PChar in TPW };
  894.  
  895.        The name of the stream.
  896.  
  897.      METHODS
  898.  
  899.      Constructor Init(name:FNameStr;mode:TOpenMode;abufsize:word);
  900.  
  901.        Open the file with the given name, and save the name.
  902.  
  903.      Destructor Done; virtual;
  904.  
  905.        Close the file.
  906.  
  907. 15.  TTempBufStream = object(TNamedBufStream)
  908.  
  909.        A temporary buffered file stream, which deletes itself when done.
  910.  
  911.      METHODS
  912.  
  913.      Constructor init(abufsize:word);
  914.  
  915.        Create a temporary file with a unique name, in the directory
  916.        pointed to by the environment varable TEMP or in the current
  917.        directory, and open it in read/write mode.
  918.  
  919.      Destructor done; virtual;
  920.  
  921.        Close and delete the temporary file.
  922.  
  923. 16.  Function TempStream(InitSize,MaxSize : longint;
  924.                         Preference:TStreamRanking):PStream;
  925.  
  926.        This procedure returns a pointer to a temporary stream from a
  927.        choice of 4, specified in the Preference array.  The first stream
  928.        type listed in the Preference array which can be successfully
  929.        created with the given sizes will be returned, or Nil if none can
  930.        be made.
  931.  
  932.      ARGUMENTS
  933.  
  934.      Initsize : longint;
  935.  
  936.        The initial size to allocate to the stream.  This many nulls will
  937.        be written to the stream, and then the position will be set to
  938.        byte 0.
  939.  
  940.      MaxSize : longint;
  941.  
  942.        The maximum size to which the stream should be allowed to grow.
  943.  
  944.      Preference : TStreamRanking;
  945.  
  946.        An array of 4 entries specifying what sort of temporary stream is
  947.        desired.  Supplied constants include:
  948.  
  949.         ForSpeed = (RAMStream, EMSStream, XMSStream, FileStream);
  950.         ForSize  = (FileStream,EMSStream, XMSStream, RAMStream);
  951.         ForSizeInMem = (EMSStream, XMSStream, RAMStream, NoStream);
  952.         ForOverlays =  (EMSStream, XMSStream, FileStream, NoStream);
  953.  
  954. 17. Stream overlay procedures
  955.  
  956.        These procedures allow overlays to be buffered on any stream or
  957.        combination of streams.  Some overlays can be loaded into EMS,
  958.        others kept on disk, and others can be put onto any other
  959.        available stream.
  960.  
  961.      PROCEDURES/FUNCTIONS
  962.  
  963.      Procedure OvrInitStream(S:PStream);
  964.  
  965.        Copies overlay segment code to S as new segments are loaded, and
  966.        does reloads from there.  You may call OvrInitStream multiple
  967.        times, and different segments will be buffered on different
  968.        streams, depending on the order in which they are loaded by the
  969.        overlay loader.
  970.  
  971.        On the first call, an exit handler is installed which will call
  972.        OvrDisposeStreams upon program termination.
  973.  
  974.      Procedure OvrDetachStream(BadS:PStream);
  975.  
  976.        Makes sure that the overlay system makes no references to BadS.
  977.        Call this before disposing of a stream which has been passed to
  978.        OvrInitStream, or you're very likely to crash.
  979.  
  980.      Procedure OvrDisposeStreams;
  981.  
  982.        Detaches and disposes of all streams being used by the overlay
  983.        system.
  984.  
  985.      Function OvrSizeNeeded:longint;
  986.  
  987.        Returns the additional size required to load any segments which
  988.        still haven't been loaded to a stream.
  989.  
  990.      Function OvrLoadAll:boolean;
  991.  
  992.        Forces all overlay segments to be copied into the stream; if
  993.        successful (true) then no more references to the overlay file
  994.        will be made.
  995.  
  996.        Warning:  This function calls OvrClearBuf, so that any overlay
  997.        files which are already in the regular overlay buffer will need
  998.        to be reloaded.
  999.  
  1000. 18.  Miscellaneous constants and types
  1001.  
  1002.      CONSTANTS
  1003.  
  1004.      stBadMode = 1;
  1005.  
  1006.        Error signalled when an operation is not permitted in the current
  1007.        mode.
  1008.  
  1009.      stStreamFail = 2;
  1010.  
  1011.        Error signalled when a stream Init failed.
  1012.  
  1013.      stBaseError = 3;
  1014.  
  1015.        Error signalled by a TFilter when the base stream has an error;
  1016.        the base stream's error number is put in the Info field.
  1017.  
  1018.      stMemError = 4;
  1019.  
  1020.        Not enough memory for operation.
  1021.  
  1022.      stSigError = 5;
  1023.  
  1024.        Problem with LZW file signature.
  1025.  
  1026.      stUsedAll = 6;
  1027.  
  1028.        XMS stream has used all of its allowed blocks.
  1029.  
  1030.      stUnsupported = 7;
  1031.  
  1032.        Operation unsupported in this stream.  TSequential signals this
  1033.        error if Seek is called.
  1034.  
  1035.      stBase2Error = 8;
  1036.  
  1037.        Error in second base in a TDupFilter; Info gets the Base2^.Error
  1038.        value.
  1039.  
  1040.      stMisMatch = 9;
  1041.  
  1042.        The two bases don't match on a read.  The Info field is set to
  1043.        the position of the mismatch in the current read buffer.
  1044.  
  1045.      BufSize : word = 2048;
  1046.  
  1047.        Buffer size to use when creating a buffered file stream in
  1048.        TempStream.
  1049.  
  1050.      TYPES
  1051.  
  1052.      TOpenMode = $3C00..$3DFF;
  1053.  
  1054.        This is the widest possible range of open modes for a TDOSStream
  1055.        descendant.  Values outside this range can cause very serious bugs in
  1056.        programs, since the high byte is used as the DOS service number
  1057.        when the file is opened.
  1058.  
  1059.      PLZWTables = ^TLZWTables;
  1060.      TLZWTables = record ...
  1061.  
  1062.        These tables are used internally to maintain the state of a
  1063.        TLZWFilter.
  1064.  
  1065.      PByte_Array = ^TByte_Array;
  1066.      TByte_Array = array[0..65520] of byte;
  1067.  
  1068.        An array type used as a buffer in several places.
  1069.  
  1070.      TStreamType = (NoStream, RAMStream, EMSStream, XMSStream, FileStream);
  1071.  
  1072.        The types of streams that TempStream can create.
  1073.  
  1074.      TStreamRanking = array[1..NumTypes] of TStreamType;
  1075.  
  1076.        An array giving the order from most preferred to least preferred
  1077.        for a temporary stream.
  1078.  
  1079. 15.  Release history and credits
  1080.  
  1081.      1.0 - First release, missing LZW.  Immediately replaced by
  1082.      1.1 - First correct release: TFilter, TEncryptFilter, TTextFilter,
  1083.            TLogFilter, TRAMStream, TNamedBufStream, TTempBufStream,
  1084.            TempStream, overlay procedures (my ideas), TLZWFilter
  1085.            (from code by Wilbert van Leijen)
  1086.      1.2 - TNulStream, TXMSStream added (from Stefan Boether)
  1087.            TBitFilter added (suggestion of Rene Seguin)
  1088.            TFilter.Done calls Flush
  1089.            TRAMStream.UseBuf and OwnMem added.
  1090.      1.3 - TDupFilter, TSequential, TChksumFilter added (my ideas),
  1091.            TCRC16Filter, TCRCARCFilter, TCRC32Filter and related procedures
  1092.            added (from code by Edwin T. Floyd, Stephen Satchell, Chuck
  1093.            Forsberg, Mark G. Mendel, R. P. Byrne, J. R. Louvau and
  1094.            probably others); TFilter.Flush added; HUFFMAN demo added.
  1095.